import { createHash } from "node:crypto";
import { logger } from "../../utils";
import { IUserStore, LoginUser } from "./interface";
import * as fs from 'node:fs'
import { DBFile } from "../../utils/dbfile";

export class UserStore implements IUserStore {
    private db_user: DBFile<Map<string, LoginUser>>;
    private deleteCallbacks: {(username: string): void}[] = []
    private mock_user?: LoginUser;
    /**
     * @param db_path 用户密码存储文件路径
     * 用户密码文件格式（密码为md5密文）: 每行一个用户
     * ```
     *      username1:password1:nickname1
     *      username2:password2:nickname2
     *      username3:password3:nickname3
     * ```
     */
    constructor (db_path: string, mock_user?: LoginUser) {
        this.mock_user = mock_user
        this.db_user = new DBFile<Map<string, LoginUser>>({
            filePath: db_path,
            watchFile: true,
            initData: new Map([
                ['admin:e10adc3949ba59abbe56e057f20f883e', { username: 'admin', nickname: '管理员' }],
                ['user:e10adc3949ba59abbe56e057f20f883e', { username: 'user', nickname: '用户' }],
            ]),
            fileToData: (filePath) => {
                const lines = fs.readFileSync(filePath, 'utf8').split(/[\r\n]+/)
                const user_map = new Map<string, LoginUser>()
                for (const line of lines) {
                    const [username, password, nickname] = line.split(':')
                    user_map.set(`${username}:${password}`, { username, nickname })
                }
                return user_map
            },
            dataToFile: (data) => {
                const lines: string[] = []
                data.forEach((v, key) => {
                    lines.push(`${key}:${v.nickname}`)
                })
                return lines.join('\n')
            },
            onFileChange: (newData, oldData) => {
                const deleteCallbacks = this.deleteCallbacks
                oldData?.forEach(function (v, key) {
                    if (!newData?.has(key)) {
                        const username = key.split(':')[0]
                        logger.info(`user: "${username}" deleted`)
                        deleteCallbacks.forEach(callback => callback(username))
                    }
                })
            }
        })
    }
    async getUser(username: string, password: string): Promise<LoginUser | undefined> {
        const pwd = createHash('md5').update(password).digest('hex')
        return this.db_user.data?.get(`${username}:${pwd}`)
    }
    onDeleteUser(callback: (username: string) => void): void {
        this.deleteCallbacks.push(callback)
    }
    async getLoginUser(): Promise<LoginUser | undefined> {
        return this.mock_user
    }
}